package com.emser.unc.server;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import javax.jdo.JDOCanRetryException;
import javax.jdo.PersistenceManager;
import javax.jdo.Query;
import javax.jdo.Transaction;

import org.datanucleus.store.appengine.query.JDOCursorHelper;

import com.emser.unc.serializable.LocationDTO;
import com.emser.unc.serializable.ResultDTO;
import com.emser.unc.server.domain.Device;
import com.emser.unc.server.domain.Seller;
import com.google.appengine.api.datastore.Cursor;

public class AppLibDevices {
	private static final int NUM_RETRIES = 5;

	@SuppressWarnings("unchecked")
	public static ResultDTO<LocationDTO> getSerialDevices(String pageCursor, int range,String userAName) {
		List<Device> devices = null, devicesCopy;
		ResultDTO<LocationDTO> result = null;
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query q = pm.newQuery(Device.class);
		q.setFilter("userA == :userAccountName");
		q.setOrdering("serialDevice asc");
		q.setRange(0, range);
		if (pageCursor != null) {
        	Cursor cursor = Cursor.fromWebSafeString(pageCursor);
        	Map<String, Object> extensionMap = new HashMap<String, Object>();
        	extensionMap.put(JDOCursorHelper.CURSOR_EXTENSION, cursor);
        	q.setExtensions(extensionMap);
        }
		 try {
			 devices = (List<Device>) q.execute(userAName);
			 if (devices != null){
				 devicesCopy = (List<Device>) pm.detachCopyAll(devices);
				 Cursor cursor = JDOCursorHelper.getCursor(devices);
			        pageCursor = cursor.toWebSafeString();
			        result = new ResultDTO<LocationDTO>();
			        result.setCursorString(pageCursor);
					result.setList(toDTO(devicesCopy));
			 }
		 }catch (Exception e) {
		      e.printStackTrace();
		      result = null;
		    }
		    finally {
		      pm.close();
		      q.closeAll();
		    }
		return result;
	}
	
	@SuppressWarnings("unchecked")
	public static Integer getSerialDevicesCount(String userAName) {
		List<Device> devices = null;
		Integer result = 0;
		PersistenceManager pm = PMF.get().getPersistenceManager();
		Query q = pm.newQuery(Device.class);
		q.setFilter("userA == :userAccountName");
		 try {
			 devices = (List<Device>) q.execute(userAName);
			 if (devices != null){
				 result = devices.size();
			 }
		 }catch (Exception e) {
		      e.printStackTrace();
		      result = null;
		    }
		    finally {
		      pm.close();
		      q.closeAll();
		    }
		return result;
	}
	
	public static ArrayList<LocationDTO> toDTO(List<Device> devices){
		ArrayList<LocationDTO> devicesDTO = new ArrayList<LocationDTO>();
        for(int i = 0;i<devices.size();i++)
        	devicesDTO.add(Device.toDTO(devices.get(i)));
        return devicesDTO;
	}
	
	public static Device getLocation(String serialDevice){
		Device deviceCopy = null;
		Device device;
		PersistenceManager pm = PMF.get().getPersistenceManager();
	    Transaction tx = null;
	    Query q = pm.newQuery(Device.class, "serialDevice == :serialParam");
	    q.setUnique(true);
	    try {
	      for (int i = 0; i < NUM_RETRIES; i++) {
	        tx = pm.currentTransaction();
	        tx.begin();
	        device = (Device) q.execute(serialDevice);
	        if (device != null)
	        	deviceCopy = pm.detachCopy(device);
	        try {
	          tx.commit();
	          break;
	        }
	        catch (JDOCanRetryException e1) {
	          if (i == (NUM_RETRIES - 1)) {
	            throw e1;
	          }
	        }
	      } 
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	      return null;
	    }
	    finally {
	      if (tx.isActive()) {
	        tx.rollback();
	      }
	      pm.close();
	      q.closeAll();
	    }
		return deviceCopy;
	}
	
	public static boolean saveLocation(LocationDTO location){
		boolean result = false;
		if(location == null)
			return result;
		Device device = null;
		PersistenceManager pm = PMF.get().getPersistenceManager();
	    Transaction tx = null;
	    Query q = pm.newQuery(Device.class, "serialDevice == :serialParam");
	    q.setUnique(true);
	    try {
	      for (int i = 0; i < NUM_RETRIES; i++) {
	        tx = pm.currentTransaction();
	        tx.begin();
	        device = (Device) q.execute(location.getSerialDevice());
	        if (device != null) {
		          device.setLatitude(location.getLatitude());
			      device.setLongitude(location.getLongitude());
			      result = true;
		    }	        
	        
	        try {
	          tx.commit();
	          break;
	        }
	        catch (JDOCanRetryException e1) {
	          if (i == (NUM_RETRIES - 1)) {
	            throw e1;
	          }
	        }
	      }
	    }
	    catch (Exception e) {
	      e.printStackTrace();
	      return false;
	    }
	    finally {
	      if (tx.isActive()) {
	        tx.rollback();
	      }
	      pm.close();
	      q.closeAll();
	    }
		return result;
	}
	
	public static boolean newDevice(Seller seller, String userAName){
		boolean result = false;
		PersistenceManager pm = PMF.get().getPersistenceManager();
		try {
			Device device = new Device();
			device.setLatitude(null);
			device.setLongitude(null);
			device.setSerialDevice(seller.getSerialDevice());
			device.setFirstName(seller.getFirstName());
			device.setLastName(seller.getLastName());
			device.setUserA(userAName);
			pm.makePersistent(device);
			result = true;
		}
	    catch (Exception e) {
	      e.printStackTrace();
	      return result;
	    }
	    finally {
	    	pm.close();
		}
	    return result;
		
		
	}
}
